/**
 * @file RegistryKey.h
 * @author livio[livliu@cisco.com]
 * @brief windows Registry Utils
 * @date 2022-02-22
 * @copyright Copyright (c) 2022
 */

#ifndef REGISTRYUTILS_H
#define REGISTRYUTILS_H

#include <Windows.h>

#include <vector>
#include <string>
#include <string_view>

/**
 * @brief windows Registry Utils
 * @note  not thread-safe
 */
class RegistryKey
{
public:
    enum Format
    {
        NativeFormat = 0,
        Registry32Format, // win32
        Registry64Format, // win64
    };

    enum ErrorCode
    {
        E_REG_SUCCESS = 0,   ///< successfully
        E_REG_NO_PERMISSION, ///< no permission
        E_REG_NOT_FIND,      ///< not found the key
        E_REG_WRONG_PATH,    ///< wrong registry path
        E_REG_UNKNOWN,       ///< unknown error>
    };

public:
    explicit RegistryKey(const std::string &registryPath, Format fmt = NativeFormat);
    explicit RegistryKey(HKEY parentKey, const std::string &subKey, Format fmt = NativeFormat);
    ~RegistryKey();

    // read value
    bool ReadSubKey(const std::string &subKey, unsigned long &value);
    bool ReadSubKey(const std::string &subKey, std::string &value);
    bool ReadSubKey(const std::string &subKey, const char *buf, size_t &bufSize);

    // write value
    bool WriteSubKey(const std::string &subKey, const unsigned long &value);
    bool WriteSubKey(const std::string &subKey, const std::string &value);
    bool WriteSubKey(const std::string &subKey, const char *buf, size_t bufSize);

    // delete key-value
    bool DeleteSubKey(const std::string &subKey);

    // delete sub tree
    bool DeleteSubTree(const std::string &subKey);

    // return all child keys name
    bool AllChildKeys(std::vector<std::string> &subKeys);

    // return all child groups name
    bool AllChildGroups(std::vector<std::string> &subGroups);

    // return HKEY
    HKEY GetKey()
    {
        return m_hKey;
    }

    // Get error code
    ErrorCode GetErrorCode()
    {
        return m_errorCode;
    }

protected:
    ErrorCode OpenKey(HKEY hParentKey, const std::string &subKey);

    ErrorCode OpenKey(const std::string &regPath);

    void CloseKey();

    bool GetHKeyInPath(std::string &regPath, HKEY &key);

    unsigned long GetAcess(Format fmt);

    void SetError(LSTATUS hr);

private:
    std::string m_regKey;
    Format m_fmt{NativeFormat};
    ErrorCode m_errorCode{E_REG_SUCCESS};

    HKEY m_hKey{nullptr};
};

#endif // REGISTRYUTILS_H